package com.randb.easyhttp.request;

import com.google.gson.reflect.TypeToken;
import com.randb.easyhttp.cache.model.CacheResult;
import com.randb.easyhttp.callback.CallClazzProxy;
import com.randb.easyhttp.callback.Callback;
import com.randb.easyhttp.callback.CallbackProxy;
import com.randb.easyhttp.func.ApiResultFunc;
import com.randb.easyhttp.func.CacheResultFunc;
import com.randb.easyhttp.func.RetryExceptionFunc;
import com.randb.easyhttp.model.ApiResult;
import com.randb.easyhttp.subscriber.CallbackSubscriber;
import com.randb.easyhttp.utils.RxUtils;

import java.lang.reflect.Type;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;

/**
 * User: RandBII
 * Date: 2020/5/28
 * Description:
 */
@SuppressWarnings(value = {"unchecked"})
public class PostRequest extends BaseBodyRequest<PostRequest> {


    public PostRequest(String url) {
        super(url);
    }

    public <T> Observable<T> execute(Class<T> clazz) {
        return execute(new CallClazzProxy<ApiResult<T>, T>(clazz) {
        });
    }

    public <T> Observable<T> execute(Type type) {
        return execute(new CallClazzProxy<ApiResult<T>, T>(type) {
        });
    }


    public <T> Observable<T> execute(CallClazzProxy<? extends ApiResult<T>, T> proxy) {
        return build().generateRequest()
                .map(new ApiResultFunc<>(proxy.getType()))
                .compose(isSyncRequest ? RxUtils._main() : RxUtils._io_main())
                .compose(rxCache.transformer(cacheMode, proxy.getCallType()))
                .retryWhen(new RetryExceptionFunc(retryCount, retryDelay, retryIncreaseDelay))
                .compose(new ObservableTransformer() {
                    @Override
                    public ObservableSource apply(@NonNull Observable upstream) {
                        return upstream.map(new CacheResultFunc<T>());
                    }
                });

    }


    public <T> Disposable execute(Callback<T> callback) {

        return execute(new CallbackProxy<ApiResult<T>, T>(callback) {
        });
    }

    private <T> Disposable execute(CallbackProxy<ApiResult<T>, T> callbackProxy) {
        Observable<CacheResult<T>> observable = build().toObservable(generateRequest(), callbackProxy);
        if (CacheResult.class != callbackProxy.getCallback().getRawType()) {
            return observable.compose(new ObservableTransformer<CacheResult<T>, T>() {
                @Override
                public ObservableSource<T> apply(Observable<CacheResult<T>> upstream) {
                    return upstream.map(new CacheResultFunc<T>());
                }
            }).subscribeWith(new CallbackSubscriber<T>(context, callbackProxy.getCallback()));
        } else {
            return observable.subscribeWith(new CallbackSubscriber<CacheResult<T>>(context,
                    callbackProxy.getCallback()));
        }
    }

    private <T> Observable<CacheResult<T>> toObservable(Observable<ResponseBody> observable,
                                                        CallbackProxy<ApiResult<T>, T> callbackProxy) {
        return observable.map(new ApiResultFunc(callbackProxy != null ?
                        callbackProxy.getType() : new TypeToken<RequestBody>() {
                }.getType())
        ).compose(isSyncRequest ? RxUtils._main() : RxUtils._io_main())
                .compose(rxCache.transformer(cacheMode, callbackProxy.getCallback().getType()))
                .retryWhen(new RetryExceptionFunc(retryCount, retryDelay, retryIncreaseDelay));

    }


}
